/*
 * Ext JS Library 0.20 Copyright(c) 2006-2008, Ext JS, LLC. licensing@extjs.com
 * 
 * http://extjs.com/license
 */

/**
 * @class Ext.air.NativeWindow
 * @extends Ext.air.NativeObservable
 * 
 * Wraps the AIR NativeWindow class to give an Ext friendly API. <br/><br/>This
 * class also adds automatic state management (position and size) for the window
 * (by id) and it can be used for easily creating "minimize to system tray" for
 * the main window in your application.<br/><br/>
 * 
 * Note: Many of the config options for this class can only be applied to NEW
 * windows. Passing in an existing instance of a window along with those config
 * options will have no effect.
 * 
 * @constructor
 * @param {Object}
 *            config
 */
Ext.air.NativeWindow = function(config) {
	Ext.apply(this, config);

	/**
	 * @type String
	 */
	this.id = this.id || Ext.uniqueId();

	this.addEvents(
			/**
			 * @event close
			 * @param {Object}
			 *            e The air event object
			 */
			'close',
			/**
			 * @event closing
			 * @param {Object}
			 *            e The air event object
			 */
			'closing',
			/**
			 * @event move
			 * @param {Object}
			 *            e The air event object
			 */
			'move',
			/**
			 * @event moving
			 * @param {Object}
			 *            e The air event object
			 */
			'moving',
			/**
			 * @event resize
			 * @param {Object}
			 *            e The air event object
			 */
			'resize',
			/**
			 * @event resizing
			 * @param {Object}
			 *            e The air event object
			 */
			'resizing',
			/**
			 * @event displayStateChange
			 * @param {Object}
			 *            e The air event object
			 */
			'displayStateChange',
			/**
			 * @event displayStateChanging
			 * @param {Object}
			 *            e The air event object
			 */
			'displayStateChanging');

	Ext.air.NativeWindow.superclass.constructor.call(this);

	if (!this.instance) {
		var options = new air.NativeWindowInitOptions();
		options.systemChrome = this.chrome;
		options.type = this.type;
		options.resizable = this.resizable;
		options.minimizable = this.minimizable;
		options.maximizable = this.maximizable;
		options.transparent = this.transparent;

		this.loader = window.runtime.flash.html.HTMLLoader.createRootWindow(
				false, options, false);
		this.loader.load(new air.URLRequest(this.file));

		this.instance = this.loader.window.nativeWindow;
	} else {
		this.loader = this.instance.stage.getChildAt(0);
	}

	var provider = Ext.state.Manager;
	var b = air.Screen.mainScreen.visibleBounds;

	var state = provider.get(this.id) || {};
	provider.set(this.id, state);

	var win = this.instance;

	var width = Math.max(state.width || this.width, 100);
	var height = Math.max(state.height || this.height, 100);

	var centerX = b.x + ((b.width / 2) - (width / 2));
	var centerY = b.y + ((b.height / 2) - (height / 2));

	var x = !Ext.isEmpty(state.x, false) ? state.x : (!Ext.isEmpty(this.x,
			false) ? this.x : centerX);
	var y = !Ext.isEmpty(state.y, false) ? state.y : (!Ext.isEmpty(this.y,
			false) ? this.y : centerY);

	win.width = width;
	win.height = height;
	win.x = x;
	win.y = y;

	win.addEventListener('move', function() {
				if (win.displayState != air.NativeWindowDisplayState.MINIMIZED
						&& win.width > 100 && win.height > 100) {
					state.x = win.x;
					state.y = win.y;
				}
			});
	win.addEventListener('resize', function() {
				if (win.displayState != air.NativeWindowDisplayState.MINIMIZED
						&& win.width > 100 && win.height > 100) {
					state.width = win.width;
					state.height = win.height;
				}
			});

	Ext.air.NativeWindowManager.register(this);
	this.on('close', this.unregister, this);

	/**
	 * @cfg {Boolean} minimizeToTray True to enable minimizing to the system
	 *      tray. Note: this should only be applied to the primary window in
	 *      your application. A trayIcon is required.
	 */
	if (this.minimizeToTray) {
		this.initMinimizeToTray(this.trayIcon, this.trayMenu);
	}

};

Ext.extend(Ext.air.NativeWindow, Ext.air.NativeObservable, {

	/**
	 * @cfg {air.NativeWindow} instance The native window instance to wrap. If
	 *      undefined, a new window will be created.
	 */

	/**
	 * @cfg {String} trayIcon The icon to display when minimized in the system
	 *      tray
	 */
	/**
	 * @cfg {NativeMenu} trayMenu Menu to display when the tray icon is right
	 *      clicked
	 */
	/**
	 * @cfg {String} trayTip Tooltip for the tray icon
	 */

	/**
	 * @cfg {String} chrome The native window chrome (defaults to 'standard',
	 *      can also be 'none').
	 */
	chrome : 'standard', // can also be none
	/**
	 * @cfg {String} type The native window type - normal, utility or
	 *      lightweight. (defaults to normal)
	 */
	type : 'normal', // can be normal, utility or lightweight
	/**
	 * @cfg {Number} width
	 */
	width : 600,
	/**
	 * @cfg {Number} height
	 */
	height : 400,
	/**
	 * @cfg {Boolean} resizable
	 */
	resizable : true,
	/**
	 * @cfg {Boolean} minimizable
	 */
	minimizable : true,
	/**
	 * @cfg {Boolean} maximizable
	 */
	maximizable : true,
	/**
	 * @cfg {Boolean} transparent
	 */
	transparent : false,

	/**
	 * Returns the air.NativeWindow instance
	 * 
	 * @return air.NativeWindow
	 */
	getNative : function() {
		return this.instance;
	},

	/**
	 * Returns the x/y coordinates for centering the windw on the screen
	 * 
	 * @return {x: Number, y: Number}
	 */
	getCenterXY : function() {
		var b = air.Screen.mainScreen.visibleBounds;
		return {
			x : b.x + ((b.width / 2) - (this.width / 2)),
			y : b.y + ((b.height / 2) - (this.height / 2))
		};
	},

	/**
	 * Shows the window
	 */
	show : function() {
		if (this.trayed) {
			Ext.air.SystemTray.hideIcon();
			this.trayed = false;
		}
		this.instance.visible = true;
	},

	/**
	 * Shows and activates the window
	 */
	activate : function() {
		this.show();
		this.instance.activate();
	},

	/**
	 * Hides the window
	 */
	hide : function() {
		this.instance.visible = false;
	},

	/**
	 * Closes the window
	 */
	close : function() {
		this.instance.close();
	},

	/**
	 * Returns true if this window is minimized
	 * 
	 * @return Boolean
	 */
	isMinimized : function() {
		return this.instance.displayState == air.NativeWindowDisplayState.MINIMIZED;
	},

	/**
	 * Returns true if this window is maximized
	 * 
	 * @return Boolean
	 */
	isMaximized : function() {
		return this.instance.displayState == air.NativeWindowDisplayState.MAXIMIZED;
	},

	/**
	 * Moves the window to the passed xy and y coordinates
	 * 
	 * @param {Number}
	 *            x
	 * @param {Number}
	 *            y
	 */
	moveTo : function(x, y) {
		this.x = this.instance.x = x;
		this.y = this.instance.y = y;
	},

	/**
	 * @param {Number}
	 *            width
	 * @param {Number}
	 *            height
	 */
	resize : function(width, height) {
		this.width = this.instance.width = width;
		this.height = this.instance.height = height;
	},

	unregister : function() {
		Ext.air.NativeWindowManager.unregister(this);
	},

	initMinimizeToTray : function(icon, menu) {
		var tray = Ext.air.SystemTray;

		tray.setIcon(icon, this.trayTip);
		this.on('displayStateChanging', function(e) {
					if (e.afterDisplayState == 'minimized') {
						e.preventDefault();
						this.hide();
						tray.showIcon();
						this.trayed = true;
					}
				}, this);

		tray.on('click', function() {
					this.activate();
				}, this);

		if (menu) {
			tray.setMenu(menu);
		}
	}
});

/**
 * Returns the first opened window in your application
 * 
 * @return air.NativeWindow
 * @static
 */
Ext.air.NativeWindow.getRootWindow = function() {
	return air.NativeApplication.nativeApplication.openedWindows[0];
};

/**
 * Returns the javascript "window" object of the first opened window in your
 * application
 * 
 * @return Window
 * @static
 */
Ext.air.NativeWindow.getRootHtmlWindow = function() {
	return Ext.air.NativeWindow.getRootWindow().stage.getChildAt(0).window;
};

/**
 * @class Ext.air.NativeWindowGroup
 * 
 * A collection of NativeWindows.
 */
Ext.air.NativeWindowGroup = function() {
	var list = {};

	return {
		/**
		 * @param {Object}
		 *            win
		 */
		register : function(win) {
			list[win.id] = win;
		},

		/**
		 * @param {Object}
		 *            win
		 */
		unregister : function(win) {
			delete list[win.id];
		},

		/**
		 * @param {String}
		 *            id
		 */
		get : function(id) {
			return list[id];
		},

		/**
		 * Closes all windows
		 */
		closeAll : function() {
			for (var id in list) {
				if (list.hasOwnProperty(id)) {
					list[id].close();
				}
			}
		},

		/**
		 * Executes the specified function once for every window in the group,
		 * passing each window as the only parameter. Returning false from the
		 * function will stop the iteration.
		 * 
		 * @param {Function}
		 *            fn The function to execute for each item
		 * @param {Object}
		 *            scope (optional) The scope in which to execute the
		 *            function
		 */
		each : function(fn, scope) {
			for (var id in list) {
				if (list.hasOwnProperty(id)) {
					if (fn.call(scope || list[id], list[id]) === false) {
						return;
					}
				}
			}
		}
	};
};

/**
 * @class Ext.air.NativeWindowManager
 * @extends Ext.air.NativeWindowGroup
 * 
 * Collection of all NativeWindows created.
 * 
 * @singleton
 */
Ext.air.NativeWindowManager = new Ext.air.NativeWindowGroup();